package com.vinoxm.rss.handler.filter;

import com.vinoxm.common.base.exception.AuthException;
import com.vinoxm.common.base.exception.RssUpdatingException;
import com.vinoxm.common.utils.StringUtils;
import com.vinoxm.rss.handler.interceptor.annotation.AwaitRssUpdate;
import com.vinoxm.rss.handler.interceptor.annotation.NeedSecret;
import com.vinoxm.rss.handler.validate.annotation.ValidateParams;
import com.vinoxm.rss.handler.validate.ControllerParamsValidator;
import com.vinoxm.rss.redis.RedisClient;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Component
@Log4j2
public class ControllerPreCheckFilterChain {

    private List<ControllerPrepareFilter> filterList;

    private ControllerPreCheckFilterChain addFilter(ControllerPrepareFilter filter) {
        if (filterList == null) {
            filterList = new ArrayList<>();
        }
        filterList.add(filter);
        return this;
    }

    @PostConstruct
    public void init() {
        addFilter((request, response, handler) -> {
            // Secret validate
            NeedSecret needSecret = handler.hasMethodAnnotation(NeedSecret.class)
                    ? handler.getMethodAnnotation(NeedSecret.class)
                    : handler.getMethod().getDeclaringClass().getAnnotation(NeedSecret.class);
            if (needSecret != null && needSecret.enable()) {
                String secret = request.getHeader("secret");
                if (StringUtils.isEmpty(secret)) {
                    throw new AuthException(String.format("[Verify Secret] %s:%s", request.getMethod(), request.getRequestURI()), "Secret is empty ");
                }
                if (!secret.equals(needSecret.value())) {
                    throw new AuthException(String.format("[Verify Secret] %s:%s", request.getMethod(), request.getRequestURI()), "Secret error ");
                }
                log.info(String.format("[Verify Secret] %s:%s -> Success!", request.getMethod(), request.getRequestURI()));
            }
        }).addFilter((request, response, handler) -> {
            // Wait Rss Update
            AwaitRssUpdate awaitRssUpdate = handler.hasMethodAnnotation(AwaitRssUpdate.class)
                    ? handler.getMethodAnnotation(AwaitRssUpdate.class)
                    : handler.getMethod().getDeclaringClass().getAnnotation(AwaitRssUpdate.class);
            if (awaitRssUpdate != null && awaitRssUpdate.value() && RedisClient.isRssUpdating()) {
                throw new RssUpdatingException();
            }
        }).addFilter(((request, response, handler) -> {
            // Validate params
            ValidateParams annotation = handler.getMethodAnnotation(ValidateParams.class);
            if (annotation != null) {
                Class<?> clazz = annotation.value();
                log.info("[Validate params] " + clazz.getName());
                ControllerParamsValidator.validate(clazz, request.getParameterMap());
                log.info("[Validate params] Success!");
            }
        }));
    }

    public void doCheck(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler) {
        for (ControllerPrepareFilter filter : filterList) {
            filter.doFilter(request, response, handler);
        }
    }
}
